import $ from 'jquery'

function createCloudCarousel (obj, options) {
  console.log({ obj })
  obj.CloudCarousel = function () {
    return this.each(function () {
      options = $.extend({
        xOrigin: null,
        yOrigin: null,
        xRadius: null,
        yRadius: null,
        farScale: 0.4,
        transforms: true,
        smooth: true,
        fps: 30,
        speed: 4,
        autoPlay: 0,
        autoPlayDelay: 3000,
        bringToFront: false,
        itemClass: 'cloud-item',
        frontItemClass: null,
        handle: 'carousel'
      },
      options)
      $(this).data(options.handle, new Carousel(this, options))
    })
  }
  obj.CloudCarousel()
}
export { createCloudCarousel }

const time = !window.performance || !window.performance.now
  ? function () {
    return +new Date()
  } : function () {
    return performance.now()
  }
var cancelFrame = window.cancelAnimationFrame || window.cancelRequestAnimationFrame
var requestFrame = window.requestAnimationFrame;
(function () {
  var vendors = ['webkit', 'moz', 'ms']
  for (var i = 0,
    count = vendors.length; i < count && !cancelFrame; i++) {
    cancelFrame = window[vendors[i] + 'CancelAnimationFrame'] || window[vendors[i] + 'CancelRequestAnimationFrame']
    requestFrame = requestFrame && window[vendors[i] + 'RequestAnimationFrame']
  }
}())
var transform = (function () {
  var vendors = ['webkit', 'moz', 'ms']
  var style = document.createElement('div').style
  var trans = 'transform' in style ? 'transform' : undefined
  for (var i = 0,
    count = vendors.length; i < count; i++) {
    var prop = vendors[i] + 'Transform'
    if (prop in style) {
      trans = prop
      break
    }
  }
  return trans
})()
// 轮播构造器
function Carousel (element, options) {
  var self = this
  var $container = $(element)
  this.items = []
  this.xOrigin = (options.xOrigin === null) ? $container.width() * 0.5 : options.xOrigin
  this.yOrigin = (options.yOrigin === null) ? $container.height() * 0.1 : options.yOrigin
  this.xRadius = (options.xRadius === null) ? $container.width() / 2.3 : options.xRadius
  this.yRadius = (options.yRadius === null) ? $container.height() / 6 : options.yRadius
  this.farScale = options.farScale
  this.rotation = this.destRotation = Math.PI / 2
  this.speed = options.speed
  this.smooth = options.smooth
  this.fps = options.fps
  this.timer = 0
  this.autoPlayAmount = options.autoPlay
  this.autoPlayDelay = options.autoPlayDelay
  this.autoPlayTimer = 0
  this.frontItemClass = options.frontItemClass
  this.onLoaded = options.onLoaded
  this.onRendered = options.onRendered
  this.onAnimationFinished = options.onAnimationFinished
  this.itemOptions = {
    transforms: options.transforms
  }
  if (options.mirror) {
    this.itemOptions.mirror = $.extend({
      gap: 2
    },
    options.mirror)
  }
  $container.css({
    position: 'relative',
    overflow: 'hidden'
  })
  this.renderItem = function (itemIndex, rotation) {
    var item = this.items[itemIndex]
    var sin = Math.sin(rotation)
    var farScale = this.farScale
    var scale = farScale + ((1 - farScale) * (sin + 1) * 0.58)
    item.moveTo(this.xOrigin + (scale * ((Math.cos(rotation) * this.xRadius) - (item.fullWidth * 0.5))), this.yOrigin + (scale * sin * this.yRadius), scale)
    return item
  }
  this.render = function () {
    var count = this.items.length
    var spacing = 2 * Math.PI / count
    var radians = this.rotation
    var nearest = this.nearestIndex()
    for (var i = 0; i < count; i++) {
      var item = this.renderItem(i, radians)
      // console.log("item----------------",item)
      if (i === nearest) $(item.element).addClass(this.frontItemClass)
      else $(item.element).removeClass(this.frontItemClass)
      radians += spacing
    }
    if (typeof this.onRendered === 'function') this.onRendered(this)
  }
  this.playFrame = function () {
    var rem = self.destRotation - self.rotation
    // console.log("22----------------"+rem)
    var now = time()
    var dt = (now - self.lastTime) * 0.002
    self.lastTime = now
    if (Math.abs(rem) < 0.003) {
      self.rotation = self.destRotation
      self.pause()
      if (typeof self.onAnimationFinished === 'function') self.onAnimationFinished()
    } else {
      self.rotation = self.destRotation - rem / (1 + (self.speed * dt))
      self.scheduleNextFrame()
    }
    self.render()
  }
  this.scheduleNextFrame = function () {
    this.lastTime = time()
    // console.log("----------------"+this.smooth+"------"+cancelFrame)
    this.timer = this.smooth && cancelFrame ? requestFrame(self.playFrame) : setTimeout(self.playFrame, 1000 / this.fps)
  }
  this.itemsRotated = function () {
    return this.items.length * ((Math.PI / 2) - this.rotation) / (2 * Math.PI)
  }
  this.floatIndex = function () {
    var count = this.items.length
    var floatIndex = this.itemsRotated() % count
    return (floatIndex < 0) ? floatIndex + count : floatIndex
  }
  this.nearestIndex = function () {
    return Math.round(this.floatIndex()) % this.items.length
  }
  this.nearestItem = function () {
    return this.items[this.nearestIndex()]
  }
  this.play = function () {
    if (this.timer === 0) this.scheduleNextFrame()
  }
  this.pause = function () {
    this.smooth && cancelFrame ? cancelFrame(this.timer) : clearTimeout(this.timer)
    this.timer = 0
  }
  this.go = function (count) {
    this.destRotation += (2 * Math.PI / this.items.length) * count
    this.play()
  }
  this.goTo = function (index) {
    var count = this.items.length
    var diff = index - (this.floatIndex() % count)
    if (2 * Math.abs(diff) > count) diff -= (diff > 0) ? count : -count
    this.destRotation = this.rotation
    this.go(-diff)
    return diff
  }
  this.deactivate = function () {
    this.pause()
    clearInterval(this.autoPlayTimer)
    if (options.buttonLeft) options.buttonLeft.unbind('click')
    if (options.buttonRight) options.buttonRight.unbind('click')
    $container.unbind('.cloud')
  }
  this.autoPlay = function () {
    this.autoPlayTimer = setInterval(function () {
      self.go(self.autoPlayAmount)
    },
    this.autoPlayDelay)
  }
  this.enableAutoPlay = function () {
    $container.bind('mouseover.cloud',
      function () {
        clearInterval(self.autoPlayTimer)
      })
    $container.bind('mouseout.cloud',
      function () {
        self.autoPlay()
      })
    this.autoPlay()
  }
  this.bindControls = function () {
    if (options.buttonLeft) {
      options.buttonLeft.bind('click',
        function () {
          self.go(-1)
          return false
        })
    }
    if (options.buttonRight) {
      options.buttonRight.bind('click',
        function () {
          self.go(1)
          return false
        })
    }
    if (options.mouseWheel) {
      $container.bind('mousewheel.cloud',
        function (event, delta) {
          self.go((delta > 0) ? 1 : -1)
          return false
        })
    }
    if (options.bringToFront) {
      $container.bind('click.cloud',
        function (event) {
          var hits = $(event.target).closest('.' + options.itemClass)
          if (hits.length !== 0) {
            var diff = self.goTo(self.items.indexOf(hits[0].item))
            if (Math.abs(diff) > 0.5) event.preventDefault()
          }
        })
    }
  }
  var items = $container.find('.' + options.itemClass)
  this.finishInit = function () {
    for (var i = 0; i < items.length; i++) {
      var item = items[i]
      if ((item.tagName === 'p') && ((item.width === undefined) || ((item.complete !== undefined) && !item.complete))) return
    }
    clearInterval(this.initTimer)
    for (i = 0; i < items.length; i++) this.items.push(new Item(items[i], this.itemOptions))
    $container.bind('mousedown onselectstart',
      function () {
        return false
      })
    if (this.autoPlayAmount !== 0) this.enableAutoPlay()
    this.bindControls()
    this.render()
    if (typeof this.onLoaded === 'function') this.onLoaded(this)
  }
  this.initTimer = setInterval(function () {
    self.finishInit()
  },
  50)
}
// 单项构造器
function Item (element, options) {
  element.item = this
  this.element = element
  if (element.tagName === 'p') {
    this.fullWidth = element.width
    this.fullHeight = element.height
  } else {
    element.style.display = 'inline-block'
    this.fullWidth = element.offsetWidth
    this.fullHeight = element.offsetHeight
  }
  element.style.position = 'absolute'
  if (options.mirror && this.element.tagName === 'p') {
    this.reflection = $(element).reflect(options.mirror).next()[0]
    var $reflection = $(this.reflection)
    this.reflection.fullHeight = $reflection.height()
    $reflection.css('margin-top', options.mirror.gap + 'px')
    $reflection.css('width', '100%')
    element.style.width = '100%'
    this.element = this.element.parentNode
    this.element.item = this
    this.element.alt = element.alt
    this.element.title = element.title
  }
  if (transform && options.transforms) this.element.style[transform + 'Origin'] = '0 0'
  this.moveTo = function (x, y, scale) {
    this.width = this.fullWidth * scale
    this.height = this.fullHeight * scale
    this.x = x
    this.y = y
    this.scale = scale
    var style = this.element.style
    style.zIndex = '' + (scale * 100) | 0
    // y += 12
    if (transform && options.transforms) {
      style[transform] = 'translate(' + x + 'px, ' + y + 'px) scale(' + scale + ') '
      style.opacity = scale
    } else {
      if (options.mirror && this.element.tagName === 'p') this.reflection.style.marginTop = (options.mirror.gap * scale) + 'px'
      style.width = this.width + 'px'
      style.left = x + 'px'
      style.top = y + 'px'
    }
  }
}
